#include <iomanip>
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <thread>
#include <chrono>
#include <tuple>
#include <variant>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/asio/property.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/unpack_properties.hpp>

namespace ipmi
{

namespace otrd
{

enum DeviceType{
    CPU,
    MEMORY,
    PCIE,
};

enum ClearType{
    CLEAR_CE,
    CLEAR_CE_PERSEC,
    CLEAR_CE_FREQ,
    CLEAR_CE_ALL,
};

// 使用tuple来存储设备的具体参数  
using CPUIdentifier = std::tuple<uint8_t>; // 例如：std::make_tuple(0) 表示CPU0  
using MemoryIdentifier = std::tuple<uint8_t, uint8_t, uint8_t>; // 例如：std::make_tuple(0, 0) 表示CPU0上的第0根内存  
using PCIEIdentifier = std::tuple<uint8_t, uint8_t, uint8_t, uint8_t>; // 根据您的需求定义具体的参数 

using PropertyValue = std::variant<uint8_t, uint32_t>;
using PropertyName = std::string;

static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
static constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
static constexpr auto dbusPropertyIntf = "org.freedesktop.DBus.Properties";

struct DeviceCECount {  
    int ce_count = 0;
    int ceCntPerSec = 0;//每秒钟产生的CE数量
    uint8_t  ceFreq = 0;//CE风暴计数   
    DeviceType type;  
    std::variant<CPUIdentifier, MemoryIdentifier, PCIEIdentifier> identifier;  
    DeviceCECount(){}
    DeviceCECount(DeviceType t, const std::variant<CPUIdentifier, MemoryIdentifier, PCIEIdentifier>& id)  
        : type(t), identifier(id) {}  
};

// 线程安全的CE计数器  
class CECounter {  
private:  
    std::unordered_map<std::string, DeviceCECount> ce_counts;  
    std::mutex mutex_;  
    static uint32_t cpuFunnel;
    static uint32_t cpuThreshold;
    static uint32_t memPcieFunnel;
    static uint32_t memPcieThreshold;
    static bool isenable;
    std::thread timer;
    // 辅助函数，用于生成设备的唯一标识符字符串  
    std::string getDeviceIdentifierString(const DeviceCECount& device);
public:  

    static auto& getBus()
    {
        static auto bus = sdbusplus::bus::new_default();
        return bus;
    }

        /**
     *  @brief Get service name by the path and interface of the DBus.
     *
     *  @param[in] path      -  D-Bus object path
     *  @param[in] interface -  D-Bus Interface
     *
     *  @return std::string  -  the D-Bus service name
     *
     */
    std::string getService(const std::string& path,
                           const std::string& interface) const;

    /** @brief Get property(type: variant)
     *
     *  @param[in] objectPath       -   D-Bus object path
     *  @param[in] interface        -   D-Bus interface
     *  @param[in] propertyName     -   D-Bus property name
     *
     *  @return The value of the property(type: variant)
     *
     *  @throw sdbusplus::exception::exception when it fails
     */
    PropertyValue getProperty(const std::string& objectPath,
                              const std::string& interface,
                              const std::string& propertyName) const;

    CECounter();
    std::string getDeviceEvent(const DeviceCECount& device);
    void addSEL(const std::string& path, const std::string& eventData);
    void addIDL(const std::string& path, const std::string& eventData);
    void addCE(const DeviceCECount& device);
    void addSELForType(uint8_t type,const std::string& eventData);
    void addIDLForType(uint8_t type,const std::string& eventData);
    void addCEFreq(const DeviceCECount& device);

    void removeCE(const DeviceCECount& device, int count);
  
     void clearCE(const DeviceCECount& device,uint8_t type);

    int getCECount(const DeviceCECount& device);
  
    bool checkAlert(const DeviceCECount& device, int threshold);

    static void setFunnelParam(DeviceType t,uint32_t funnel_l)
    {
        std::cout << "FaultPredict:setFunnelParam: " << " type= " << t << " funnel= " << funnel_l << std::endl;
        switch(t)
        {
            case CPU:
                cpuFunnel = funnel_l;
            break;
            case MEMORY:
            case PCIE:
                memPcieFunnel = funnel_l;
            break;
        }
    }

    static void setThresholdParam(DeviceType t, uint32_t threshold_l)
    {
        std::cout << "FaultPredict:setThresholdParam: " << " type= " << t << "threshold=" << threshold_l << std::endl;
        switch(t)
        {
            case CPU:
                cpuThreshold = threshold_l;
            break;
            case MEMORY:
            case PCIE:
                memPcieThreshold = threshold_l;
            break;
        }
    }

    static void setEnableStatus(bool status)
    {
        std::cout << "FaultPredict:setEnableStatus: " << "isenable=" << status << std::endl;
        isenable = status;
    }

    // 定时器回调函数  
    void timerCallback(void);
};  

}//otrd
}//ipmi

